/*******************************************************************************
 @file    dev_I2c.c
 @author  H.M.Shim (elecage@gmail.com)
 @version
 @date    2013. 7. 29.
 @brief
 ******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2013 <copyright holders>

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "usbstdio.h"
#include "devio.h"
#include "dev_gpio.h"
#include "dev_I2c.h"
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_it.h"
#include "cmdline.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define DEV_I2C1_DEVICE_NAME ((int8_t*)"i2c1")	/**< @brief I2C 1번 포트 장치명 */
#define DEV_I2C2_DEVICE_NAME ((int8_t*)"i2c2")	/**< @brief I2C 2번 포트 장치명 */
#define DEV_I2C3_DEVICE_NAME ((int8_t*)"i2c3")	/**< @brief I2C 3번 포트 장치명 */
/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

I2C_InitTypeDef i2c_initStructure;

Dev_I2c_flag devI2cFlag[NUM_I2C];
int8_t *devI2cName[NUM_I2C] = { DEV_I2C1_DEVICE_NAME,
DEV_I2C2_DEVICE_NAME,
DEV_I2C3_DEVICE_NAME };

InterruptHandleFunc i2cIsrEvFunc[NUM_I2C] = { HardFault_Handler,
		HardFault_Handler, HardFault_Handler };
InterruptHandleFunc i2cIsrErFunc[NUM_I2C] = { HardFault_Handler,
		HardFault_Handler, HardFault_Handler };

I2C_TypeDef* I2C_Type[NUM_I2C] = { I2C1, I2C2, I2C3 };
int32_t i2cTimeout = 0x00;
/* Private function prototypes -----------------------------------------------*/
void i2cTimeOut_UserCallback(void);
/* Private functions ---------------------------------------------------------*/
int32_t registerDev_I2c(void) {
	int i;
	DeviceStructure devStructure;
	for (i = 0; i < NUM_I2C; i++) {
		devStructure.dd = Dev_I2C1 + i;
		devStructure.devname = devI2cName[i];
		devStructure.openFunc = dev_I2cOpen;
		devStructure.readFunc = dev_I2cRead;
		devStructure.writeFunc = dev_I2cWrite;
		devStructure.ioctlFunc = dev_I2cIoctl;
		devStructure.closeFunc = dev_I2cClose;
#ifdef USE_CMDLINE
		devStructure.openCmdFunc = dev_I2cOpenCmd;
		devStructure.readCmdFunc = dev_I2cReadCmd;
		devStructure.writeCmdFunc = dev_I2cWriteCmd;
		devStructure.ioctlCmdFunc = dev_I2cIoctlCmd;
		devStructure.closeCmdFunc = dev_I2cCloseCmd;
#endif /* USE_CMDLINE */

		devI2cFlag[i].stat = 0;

		registerDevice(devStructure);
	}

	return 0;
}


int32_t dev_I2cOpen(const int8_t* devname, int32_t flags) {
	int32_t devNum;
	I2C_InitTypeDef I2C_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	if (strcmp((const char*) devname, (const char*) DEV_I2C1_DEVICE_NAME)
			== 0) {
		devNum = 0;
	} else if (strcmp((const char*) devname, (const char*) DEV_I2C2_DEVICE_NAME)
			== 0) {
		devNum = 1;
	} else if (strcmp((const char*) devname, (const char*) DEV_I2C3_DEVICE_NAME)
			== 0) {
		devNum = 2;
	}



	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	switch (devNum) {
	case 0: /* I2C Port 1 */
		RCC_AHB1PeriphClockCmd(I2C1_SDA_GPIO_CLK, ENABLE);
		RCC_AHB1PeriphClockCmd(I2C1_SCL_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C1_SDA_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C1_SCL_GPIO_CLK, ENABLE);

		GPIO_InitStructure.GPIO_Pin = I2C1_SDA_PIN;
		GPIO_Init(I2C1_SDA_GPIO_PORT, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = I2C1_SCL_PIN;
		GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStructure);

		GPIO_PinAFConfig(I2C1_SDA_GPIO_PORT, I2C1_SDA_SOURCE, I2C1_SDA_AF);
		GPIO_PinAFConfig(I2C1_SCL_GPIO_PORT, I2C1_SCL_SOURCE, I2C1_SCL_AF);
		break;
	case 1: /* I2C Port 2 */
		RCC_AHB1PeriphClockCmd(I2C2_SDA_GPIO_CLK, ENABLE);
		RCC_AHB1PeriphClockCmd(I2C2_SCL_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C2_SDA_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C2_SCL_GPIO_CLK, ENABLE);

		GPIO_InitStructure.GPIO_Pin = I2C2_SDA_PIN;
		GPIO_Init(I2C2_SDA_GPIO_PORT, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = I2C2_SCL_PIN;
		GPIO_Init(I2C2_SCL_GPIO_PORT, &GPIO_InitStructure);
		GPIO_PinAFConfig(I2C2_SDA_GPIO_PORT, I2C2_SDA_SOURCE, I2C2_SDA_AF);
		GPIO_PinAFConfig(I2C2_SCL_GPIO_PORT, I2C2_SCL_SOURCE, I2C2_SCL_AF);
		break;
	case 2: /* I2C Port 3 */
		RCC_AHB1PeriphClockCmd(I2C3_SDA_GPIO_CLK, ENABLE);
		RCC_AHB1PeriphClockCmd(I2C3_SCL_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C3_SDA_GPIO_CLK, ENABLE);
		RCC_APB1PeriphResetCmd(I2C3_SCL_GPIO_CLK, ENABLE);

		GPIO_InitStructure.GPIO_Pin = I2C3_SDA_PIN;
		GPIO_Init(I2C3_SDA_GPIO_PORT, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = I2C3_SCL_PIN;
		GPIO_Init(I2C3_SCL_GPIO_PORT, &GPIO_InitStructure);
		GPIO_PinAFConfig(I2C3_SDA_GPIO_PORT, I2C3_SDA_SOURCE, I2C3_SDA_AF);
		GPIO_PinAFConfig(I2C3_SCL_GPIO_PORT, I2C3_SCL_SOURCE, I2C3_SCL_AF);
	}
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 << devNum, ENABLE);
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	if ((flags & DEV_FLAG_I2C_FAST_MODE) == DEV_FLAG_I2C_FAST_MODE) {
		I2C_InitStructure.I2C_DutyCycle = I2C_FAST_DUTYCYCLE;
		I2C_InitStructure.I2C_ClockSpeed = I2C_FAST_SPEED;
		devI2cFlag[devNum].speedMode = DEV_FLAG_I2C_FAST_MODE;
	} else {
		I2C_InitStructure.I2C_DutyCycle = I2C_DEFAULT_DUTYCYCLE;
		I2C_InitStructure.I2C_ClockSpeed = I2C_DEFAULT_SPEED;
		devI2cFlag[devNum].speedMode = 0;
	}
	if ((flags & DEV_FLAG_I2C_10BITS_ADDRESS) == DEV_FLAG_I2C_10BITS_ADDRESS) {
		I2C_InitStructure.I2C_AcknowledgedAddress =
				I2C_AcknowledgedAddress_10bit;
	} else {
		I2C_InitStructure.I2C_AcknowledgedAddress =
				I2C_AcknowledgedAddress_7bit;
	}
	I2C_InitStructure.I2C_OwnAddress1 = I2C_OWN_ADDRESS;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;

	I2C_Init(I2C_Type[devNum], &I2C_InitStructure);
	I2C_Cmd(I2C_Type[devNum], ENABLE);

	if ((flags & DEV_FLAG_I2C_10BITS_ADDRESS) == DEV_FLAG_I2C_10BITS_ADDRESS) {
		devI2cFlag[devNum].addressMode = DEV_FLAG_I2C_10BITS_ADDRESS;
	} else {
		devI2cFlag[devNum].addressMode = DEV_FLAG_I2C_7BITS_ADDRESS;
	}


	if((flags & DEV_FLAG_MAP_SIZE_1) == DEV_FLAG_MAP_SIZE_1) {
		devI2cFlag[devNum].mapSize = 1;
	} else if((flags & DEV_FLAG_MAP_SIZE_2) == DEV_FLAG_MAP_SIZE_2) {
		devI2cFlag[devNum].mapSize = 2;
	} else if((flags & DEV_FLAG_MAP_SIZE_4) == DEV_FLAG_MAP_SIZE_4) {
		devI2cFlag[devNum].mapSize = 4;
	} else {
		return DEV_ERR_INVALID_ARG;
	}
	I2C_ClearFlag(I2C_Type[devNum], I2C_FLAG_BUSY);
	devI2cFlag[devNum].timeout = ((uint32_t) 0xffff);
	devI2cFlag[devNum].stat |= DEV_STAT_OPEN;
	return Dev_I2C1 + devNum; /**< Device Descriptor를 리턴 */
}

ssize_t dev_I2cWrite(int32_t dd, const void *buf, size_t n) {
	size_t i = 1;
	uint8_t* data = (uint8_t*) buf;
	int32_t devNum = dd - Dev_I2C1;
	if ((devI2cFlag[devNum].stat & DEV_STAT_OPEN) == 0) {
		return DEV_ERR_NOT_OPEN;
	}
	i2cTimeout = devI2cFlag[devNum].timeout;
	while((I2C_GetFlagStatus(I2C_Type[devNum], I2C_FLAG_BUSY)) &&  (i2cTimeout > 0x00));
	if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
	}
	I2C_GenerateSTART(I2C_Type[devNum], ENABLE);
	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum], I2C_EVENT_MASTER_MODE_SELECT))
			&& (i2cTimeout > 0x00));

	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}

	if (devI2cFlag[devNum].addressMode == DEV_FLAG_I2C_10BITS_ADDRESS) {

		I2C_SendData(I2C_Type[devNum],
				(((devI2cFlag[devNum].address & 0xFF00) >> 7) | 0xF0));

		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_MODE_ADDRESS10)) && (i2cTimeout > 0x00))
			;
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Transmitter);

	} else {
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Transmitter);
	}

	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum],
			I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (i2cTimeout > 0x00));
	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}
	if(devI2cFlag[devNum].mapSize == 1) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	} else if(devI2cFlag[devNum].mapSize == 2) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 8 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	}

	else if(devI2cFlag[devNum].mapSize == 4) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 24 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map >> 16 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 8 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	}

	for (i = 0; i < n; i++) {

		I2C_SendData(I2C_Type[devNum], data[i]);
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED))
				&& (i2cTimeout != 0x00))
			;
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}

	}

	I2C_GenerateSTOP(I2C_Type[devNum], ENABLE);
//	I2C_ClearFlag(I2C_Type[devNum], I2C_FLAG_BUSY);
	return i;
}

ssize_t dev_I2cRead(int32_t dd, void *buf, size_t nbytes) {
	size_t i = 1;
	uint8_t* data = buf;
	int32_t devNum = dd - Dev_I2C1;
	if ((devI2cFlag[devNum].stat & DEV_STAT_OPEN) == 0) {
		return DEV_ERR_NOT_OPEN;
	}
	i2cTimeout = devI2cFlag[devNum].timeout;
	while((I2C_GetFlagStatus(I2C_Type[devNum], I2C_FLAG_BUSY)) &&  (i2cTimeout > 0x00));
	if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
	}
	I2C_GenerateSTART(I2C_Type[devNum], ENABLE);
	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum], I2C_EVENT_MASTER_MODE_SELECT))
			&& (i2cTimeout > 0x00));

	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}

	if (devI2cFlag[devNum].addressMode == DEV_FLAG_I2C_10BITS_ADDRESS) {

		I2C_SendData(I2C_Type[devNum],
				(((devI2cFlag[devNum].address & 0xFF00) >> 7) | 0xF0));

		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_MODE_ADDRESS10)) && (i2cTimeout > 0x00))
			;
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Transmitter);

	} else {
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Transmitter);
	}

	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum],
			I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (i2cTimeout > 0x00));
	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}
	if(devI2cFlag[devNum].mapSize == 1) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	} else if(devI2cFlag[devNum].mapSize == 2) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 8 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	}

	else if(devI2cFlag[devNum].mapSize == 4) {
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 24 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map >> 16 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map>> 8 & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_SendData(I2C_Type[devNum], (uint8_t)(devI2cFlag[devNum].map & 0x00ff));
		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
	}
//	I2C_GenerateSTOP(I2C_Type[devNum], ENABLE);
	/** Read 모드로 다시 스타트 비트를 전송한다. */
	I2C_GenerateSTART(I2C_Type[devNum], ENABLE);
	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum], I2C_EVENT_MASTER_MODE_SELECT))
			&& (i2cTimeout > 0x00));

	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}

	if (devI2cFlag[devNum].addressMode == DEV_FLAG_I2C_10BITS_ADDRESS) {
		I2C_SendData(I2C_Type[devNum],
				(((devI2cFlag[devNum].address & 0xFF00) >> 7) | 0xF0));

		i2cTimeout = devI2cFlag[devNum].timeout;
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_MODE_ADDRESS10)) && (i2cTimeout != 0x00))	;
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Receiver);

	} else if (devI2cFlag[devNum].addressMode == DEV_FLAG_I2C_7BITS_ADDRESS) {
		I2C_Send7bitAddress(I2C_Type[devNum],
				(uint8_t) (devI2cFlag[devNum].address & 0x00FF),
				I2C_Direction_Receiver);
	}

	i2cTimeout = devI2cFlag[devNum].timeout;
	while ((!I2C_CheckEvent(I2C_Type[devNum],
			I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) && (i2cTimeout > 0x00));
	if (i2cTimeout == 0) {
		i2cTimeOut_UserCallback();
	}

	for(i = 0 ; i < nbytes ; i++ ) {
		if( i < nbytes - 1) {
			I2C_AcknowledgeConfig(I2C_Type[devNum], ENABLE);
		}else {
			I2C_AcknowledgeConfig(I2C_Type[devNum], DISABLE);
		}
		while ((!I2C_CheckEvent(I2C_Type[devNum],
				I2C_EVENT_MASTER_BYTE_RECEIVED)) && (i2cTimeout > 0x00));
		if (i2cTimeout == 0) {
			i2cTimeOut_UserCallback();
		}
		*data = I2C_ReceiveData(I2C_Type[devNum]);
		data++;
	}
/*
	while ((!I2C_CheckEvent(I2C_Type[devNum],
			I2C_EVENT_MASTER_BYTE_RECEIVED)) && (timeout > 0x00));
	if (timeout == 0) {
		timeOut_UserCallback();
	}
	*/
	I2C_GenerateSTOP(I2C_Type[devNum], ENABLE);

//	I2C_ClearFlag(I2C_Type[devNum], I2C_FLAG_BUSY);
	return i;
}

ssize_t dev_I2cIoctl(int32_t dd, int32_t request, void* data) {
	int32_t devNum = dd - Dev_I2C1;

	if ((devI2cFlag[devNum].stat & DEV_STAT_OPEN) == 0) {
		return DEV_ERR_NOT_OPEN;
	}

	switch (request) {
	case DEV_I2C_SET_ADDR_MODE:
		devI2cFlag[devNum].addressMode = *((int8_t*)data);
		break;
	case DEV_I2C_SET_ADDR: /**< @brief I2C 읽기/쓰기 주소 선택 */
		devI2cFlag[devNum].address = *((uint16_t*)data);
		break;
	case DEV_I2C_SET_MAP_SIZE:				/**< @brief MAP의 크기 지정 */
		devI2cFlag[devNum].mapSize = *((uint8_t*)data);
		break;
	case DEV_I2C_SET_MAP:
		switch(devI2cFlag[devNum].mapSize) {
		case 1:
			devI2cFlag[devNum].map = *((uint8_t *)data) & 0xff;
			break;
		case 2:
			devI2cFlag[devNum].map = *((uint16_t *)data) & 0xffff;
			break;
		case 4:
			 devI2cFlag[devNum].map = *((uint32_t *)data);
			break;
		default:
			return DEV_ERR_INVALID_ARG;
		}
		break;
	case DEV_I2C_SET_SPEED: /**< @brief I2C 클록 속도 설정 */
		devI2cFlag[devNum].speedMode = *((int8_t*)data);
		/* TODO Speed를 바꾸는 I2C 설정이 필요함.*/
		break;
	case DEV_I2C_SET_TIMEOUT: /**< @brief I2C의 타임아웃 시간 설정 */
		devI2cFlag[devNum].timeout =*((uint32_t*)data);
		break;
	case DEV_I2C_SET_MASTER: /**< @brief 장치를 I2C 마스터로 설정 */
		break;
	case DEV_I2C_SET_SLAVE: /**< @brief 장치를 I2C 슬레이브로 설정 */
		break;
	case DEV_I2C_SET_ACK_MODE:
		break;

	case DEV_I2C_GET_ADDR_MODE:
		*((int8_t*)data) = devI2cFlag[devNum].addressMode;
		break;
	case DEV_I2C_GET_ADDR: /**< @brief I2C 읽기/쓰기 주소  가져오기*/
		*((uint16_t*)data) = devI2cFlag[devNum].address;
		break;
	case DEV_I2C_GET_MAP_SIZE:				/**< @brief MAP의 크기 지정 */
		*((uint8_t*)data) = devI2cFlag[devNum].mapSize ;
			break;
	case DEV_I2C_GET_MAP:
		switch(devI2cFlag[devNum].mapSize) {
		case 1:
			*((uint8_t *)data) = (uint8_t)(devI2cFlag[devNum].map & 0xff);
			break;
		case 2:
			*((uint16_t *)data) = (uint16_t)(devI2cFlag[devNum].map & 0xffff);
			break;
		case 4:
			 *((uint32_t *)data) = devI2cFlag[devNum].map ;
			break;
		default:
			return DEV_ERR_INVALID_ARG;
		}
		break;
	case DEV_I2C_GET_SPEED: /**< @brief I2C 클록 속도  가져오기 */
		*((int8_t*)data) = devI2cFlag[devNum].speedMode;
		break;
	case DEV_I2C_GET_TIMEOUT: /**< @brief I2C의 타임아웃 시간 가져오기 */
		*((uint32_t*)data) = devI2cFlag[devNum].timeout;
		break;
	case DEV_I2C_GET_MASTER: /**< @brief 장치 I2C 마스터이면 1, 슬레이브이면 0 */
		break;
	case DEV_I2C_GET_SLAVE: /**< @brief 장치 I2C 슬레이브이면 1, 슬레이브이면 0 */
		break;
	case DEV_I2C_CLEAR_BUSY:
		I2C_ClearFlag(I2C_Type[devNum], I2C_FLAG_BUSY);
		break;
	}
	return 0;
}

int32_t dev_I2cClose(int32_t dd) {
	int32_t devNum = dd - Dev_I2C1;
	if ((devI2cFlag[devNum].stat & DEV_STAT_OPEN) == 0) {
		return DEV_ERR_NOT_OPEN;
	}

	devI2cFlag[devNum].stat &= ~(DEV_STAT_OPEN);

	I2C_DeInit(I2C_Type[devNum]);

	return 0;
}

void dev_I2cConfigInt(uint8_t portsource, EXTI_Config* config) {

}

#ifdef USE_CMDLINE

int32_t dev_I2cOpenCmd(int32_t argc, int8_t *argv[]) {
	int32_t flags = 0;
	int32_t k = 0;
	int32_t err = 0;
	if(argc < 3)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;

	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {

			for(k = 2 ; k < argc ; k++) {

				if(strcmp((char*)argv[k], "readonly")  == 0) {
					flags |= DEV_RDONLY;
				}
				if(strcmp((char*)argv[k], "writeonly") == 0) {
					flags |= DEV_WRONLY;
				}
				if(strcmp((char*)argv[k], "readwrite") == 0) {
					flags |= DEV_RDWR;
				}
				if(strcmp((char*)argv[k], DEV_ARG_I2C_ADDRESS_10BIT) == 0) {
					flags |= DEV_FLAG_I2C_10BITS_ADDRESS;
					flags &= ~(DEV_FLAG_I2C_7BITS_ADDRESS);
				}
				if(strcmp((char*)argv[k],DEV_ARG_I2C_ADDRESS_7BIT) == 0) {
					flags |= DEV_FLAG_I2C_7BITS_ADDRESS;
					flags &= ~(DEV_FLAG_I2C_10BITS_ADDRESS);
				}
				if(strcmp((char*)argv[k],DEV_ARG_I2C_SPEED_FAST) == 0) {
					flags |= (DEV_FLAG_I2C_FAST_MODE);
				}
				if(strcmp((char*)argv[k],DEV_ARG_I2C_SPEED_NORMAL) == 0) {
					flags &= ~(DEV_FLAG_I2C_FAST_MODE);
				}

				if(strcmp((char*)argv[k],DEV_ARG_I2C_MAP_SIZE_1) == 0) {
					flags |= DEV_FLAG_MAP_SIZE_1;
					flags &= ~(DEV_FLAG_MAP_SIZE_2 | DEV_FLAG_MAP_SIZE_4);
				}
				if(strcmp((char*)argv[k],DEV_ARG_I2C_MAP_SIZE_2) == 0) {
					flags |= DEV_FLAG_MAP_SIZE_2;
					flags &= ~(DEV_FLAG_MAP_SIZE_1 | DEV_FLAG_MAP_SIZE_4);
				}
				if(strcmp((char*)argv[k],DEV_ARG_I2C_MAP_SIZE_4) == 0) {
					flags |= DEV_FLAG_MAP_SIZE_4;
					flags &= ~(DEV_FLAG_MAP_SIZE_2 | DEV_FLAG_MAP_SIZE_1);
				}
			}
			err = dev_I2cOpen(device->devname, flags);
			if(err < 0) {
				usbPrintf((int8_t*)"error occered.\n");
				return CMDLINE_INVALID_ARGS;
			} else {
				usbPrintf((int8_t*)"Device %s is Opened.\n ", device->devname);
				return 0;
			}
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
int32_t dev_I2cReadCmd(int32_t argc, int8_t *argv[]) {
	if(argc < 2)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	uint8_t readData;
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_I2cRead(device->dd, &readData, 1);
			usbPrintf((int8_t*)"read %s : %4x", argv[1], readData);
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
int32_t dev_I2cWriteCmd(int32_t argc, int8_t *argv[]) {
	if(argc < 3)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	uint8_t writeData = (uint8_t)atoi((const char*)argv[2]);
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_I2cWrite(device->dd, &writeData, 1);
			usbPrintf((int8_t*)"write %s : %4x", argv[1], writeData);
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
int32_t dev_I2cIoctlCmd(int32_t argc, int8_t *argv[]) {
	if(argc < 3)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	uint8_t data;
	uint8_t bit8Map;
	uint16_t bit16Map;
	uint32_t bit32Map;
	ssize_t err;
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			if(strcmp(DEV_ARG_I2C_SET_ADDRESS, (char*)argv[2]) == 0	) {
				if(argc < 4)
					return CMDLINE_TOO_FEW_ARGS;

				data = (uint8_t)atoi((char*)argv[3]);
				usbPrintf((int8_t*)"set address request %d\n", data);
				err = dev_I2cIoctl(device->dd, DEV_I2C_SET_ADDR, &data);
				if(err != 0) {
					usbPrintf((int8_t*)"%s error occurred\n", argv[2]);
				} else {
					usbPrintf((int8_t*)"i2c set address %2x\n", data);
				}
				return 0;
			} else if(strcmp(DEV_ARG_I2C_GET_ADDRESS, (char*)argv[2]) == 0) {
				if(argc < 3)
					return CMDLINE_TOO_FEW_ARGS;

				err = dev_I2cIoctl(device->dd, DEV_I2C_GET_ADDR, &data);
				if(err != 0) {
					usbPrintf((int8_t*)"%s error occurred\n", argv[2]);
				} else {
					usbPrintf((int8_t*)"i2c get address %2x\n", data);
				}
				return 0;
			} else if(strcmp(DEV_ARG_I2C_SET_MAP, (char*)argv[2]) == 0) {
				if(argc < 4)
					return CMDLINE_TOO_FEW_ARGS;
				else {
					err = dev_I2cIoctl(device->dd, DEV_I2C_GET_MAP_SIZE, &data);
					if(data == 1) {
						bit8Map = (uint8_t)atoi((const char*)argv[3]);
						err = dev_I2cIoctl(device->dd, DEV_I2C_SET_MAP, &bit8Map);
					} else if(data == 2) {
						bit16Map = (uint16_t)atoi((const char*)argv[3]);
						err = dev_I2cIoctl(device->dd, DEV_I2C_SET_MAP, &bit16Map);
					} else if(data == 4) {
						bit32Map = (uint32_t)atoi((const char*)argv[3]);
						err = dev_I2cIoctl(device->dd, DEV_I2C_SET_MAP, &bit32Map);
					}
				}
			} else if(strcmp(DEV_ARG_I2C_GET_MAP, (char*)argv[2]) == 0) {
				if(argc < 3)
					return CMDLINE_TOO_FEW_ARGS;
				else {
					err = dev_I2cIoctl(device->dd, DEV_I2C_GET_MAP_SIZE, &data);
					if(data == 1) {
						err = dev_I2cIoctl(device->dd, DEV_I2C_GET_MAP, &bit8Map);
						usbPrintf((int8_t*)"Map address = %2x\n", bit8Map);
					} else if(data == 2) {
						err = dev_I2cIoctl(device->dd, DEV_I2C_GET_MAP, &bit16Map);
						usbPrintf((int8_t*)"Map address = %4x\n", bit16Map);
					} else if(data == 4) {
						err = dev_I2cIoctl(device->dd, DEV_I2C_GET_MAP, &bit32Map);
						usbPrintf((int8_t*)"Map address = %8x\n", bit32Map);
					}
				}
			} else if(strcmp(DEV_ARG_I2C_SET_MAP_SIZE, (char*)argv[2]) == 0) {

			} else if(strcmp(DEV_ARG_I2C_GET_MAP_SIZE, (char*)argv[2]) == 0) {

			} else if(strcmp(DEV_ARG_I2C_SET_MASTER, (char*)argv[2]) == 0) {

			} else if(strcmp(DEV_ARG_I2C_SET_SLAVE, (char*)argv[2]) == 0) {

			} else if(strcmp(DEV_ARG_I2C_GET_MS, (char*)argv[2]) == 0) {

			} else if(strcmp(DEV_ARG_I2C_CLEAR_BUSY, (char*)argv[2]) == 0) {
				dev_I2cIoctl(device->dd, DEV_I2C_CLEAR_BUSY, 0)	;
			}
				/*
			dev_I2cWrite(device->dd, &writeData, 1);
			usbPrintf((int8_t*)"write %s : %4x", argv[1], writeData);
			return 0;
			*/
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
int32_t dev_I2cCloseCmd(int32_t argc, int8_t *argv[]) {

	if(argc < 2)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_I2cClose(device->dd);
			usbPrintf((int8_t*)"close %s ", argv[1]);
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
#endif /* USE_CMDLINE */

void i2cTimeOut_UserCallback(void) {
	usbPrintf((int8_t*)"I2C Timeout\r\n");
}
